package roborally.model;

import java.io.*;
import java.util.*;
import roborally.model.interfaces.*;
import be.kuleuven.cs.som.annotate.*;

/** 
 * A class representing a Robot with a position, orientation and energy-level, and possibly an associated field and program.
 * @invar	The energy-level of the robot is always positive and smaller than or equal to maxEnergy and maxEnergy has to be positive as well.
 * 			|EnergyAmount.isValidEnergy(getEnergy(), getMaxEnergy())
 * @invar	The robot always has a valid orientation. This means that its Enum Orientation instance should always be effective.
 * 			|Orientation.isValidOrientation(this.getOrientation())
 * @Extends	Element
 * @Implements	Terminatable
 * @Implements	EnergyHolder
 * @version 3.0
 * @author Daan Camps, Jonas Willaeys
 */
public class Robot extends Element implements Terminatable, EnergyHolder{

	//****************************** Constructors *******************************************************************************
	/**
	 * Initialize a new Robot via this default constructor. This Robot has an energy-level equal to its maximum energy-level of EMAX_MAX Ws,
	 * and is oriented as Orientation.RIGHT.
	 * @effect This new Robot is initialized with a full energy-level of EMAX_MAX Ws, and oriented as Orientation.RIGHT.
	 * 		   |this(Orientation.RIGHT, EMAX_MAX, EMAX_MAX)
	 */
	public Robot() //default constructor
	{
		//assign default values
		this(Orientation.RIGHT, EMAX_MAX, EMAX_MAX);
	}
	
	/**
	 * Initialize a new Robot via this constructor. This Robot has an energy-level equal to EnergyAmount energy
	 * and is as Orientation orientation.
	 * @param 	orientation
	 * 			the orientation of the newly initialized robot given as an Orientation Enum instance of RIGHT, DOWN, LEFT or UP.
	 * @param 	energy
	 * 			the energy-level of the newly initialized robot
	 * @pre		The energy-level given as parameter should be valid.
	 * 			|EnergyAmount.isValidEnergy(energy,EMAX_MAX)
	 * @effect 	The new robot is initialized according to the parameters and default maxEnergy of EMAX_MAX
	 * 			|this(orientation, energy, EMAX_MAX)
	 */
	public Robot(Orientation orientation, EnergyAmount energy)
	{
		this(orientation, energy, EMAX_MAX);
	}
	
	/**
	 * @param 	orientation
	 * 			the orientation of the newly initialized robot given as an Orientation Enum instance of UP,RIGHT,DOWN or LEFT.
	 * @param 	energy
	 * 			the energy-level of the newly initialized robot
	 * @param	maxEnergy
	 * 			the maximum energy-level of the newly initialized robot
	 * @pre		The energy-levels given as parameter should be valid.
	 * 			|EnergyAmount.isValidEnergy(energy,maxEnergy)
	 * @effect	initialize all instance variables according to parameters
	 * 			|setEnergy(energy), setMaxEnergy(maxEnergy), setOrientation(orientation) 
	 */
	public Robot(Orientation orientation, EnergyAmount energy, EnergyAmount maxEnergy)
	{
		if(!Orientation.isValidOrientation(orientation)) orientation = Orientation.RIGHT; //total way of dealing with invalid orientation
		this.setOrientation(orientation);
		this.setEnergy(energy);
		this.setMaxEnergy(maxEnergy);	
	}

	//---------------------------------------------------------------------------------------------------------------------------------
	
	
	//****************************** attributes ***************************************************************************************
	//ITEMS
	/**
	 * myItems is a HashSet of Item objects belonging to the robot
	 */
	private List<Item> myItems = new ArrayList<Item>();
	
	/**
	 * A method that adds an item object to the HashSet of Item objects belonging to the robot
	 * @param 	item
	 * 		  	The item object that needs to be added to the HashSet of Item objects belonging to the robot
	 * @post 	The Robot has the item given as a parameter as a possession if this item is not terminated
	 * 		   	|if(!item.isTerminated()) new.hasItem(item) == true
	 * @post	if the item is terminated, then the item will not be added
	 * 			|if(item.isTerminated()) new.hasItem(item) == false
	 * @throws 	IllegalArgumentException
	 * 			An IllegalArgumentException is thrown if the argument 'item' is the null reference.
	 * 			|item == null 
	 */
	@Raw
	public void addItem(Item item) throws IllegalArgumentException {
		if(item == null) throw new IllegalArgumentException("Argument 'item' == null");
		if(item.isTerminated()) return; //no terminated items can be possessed by the robot.
		getItems().add(item);
		Collections.sort(getItems()); //keep the list sorted by weight (heaviest first), using the compareTo method of Item
	}
	
	/**
	 * A method that removes an item object from the HashSet of Item objects belonging to the robot
	 * @param 	item
	 *        	The item object that needs to be removed from the HashSet of Item objects belonging to the robot
	 * @post 	The robot doesn't have the item given as a parameter as a possession
	 * 		   	|new.hasItem(item) == false 
	 * @return 	True if the item was present and then removed, false if the item object was not present in the set.
	 * @throws 	IllegalArgumentException
	 *         	An IllegalArgumentException is thrown if the item given as a parameter is null
	 */
	@Raw
	public boolean removeItem(Item item) throws IllegalArgumentException {
		if(item == null) throw new IllegalArgumentException("Argument 'item' == null");
		return getItems().remove(item); //returns true if the item was present and then removed, false if the item object was not present in the list.
	}
	
	/**
	 * A method that checks whether or not a particular Item object, given as a parameter, belongs to the robot
	 * @param 	item
	 * 		  	The item object which can or cannot be a possession of the robot
	 * @return 	true if the given item belongs to the robot's possessions, false otherwise
	 * 		   	|result == getItems().contains(item)
	 */
	public boolean hasItem(Item item){
		return getItems().contains(item);
	}
	
	/**
	 * A method that returns the Item object belonging to the robot as a Set
	 * @return myItems
	 */
	@Basic @Raw
	public List<Item> getItems(){
		return myItems;
	}
	
	/**
	 * A methods that returns the total weight of the robots possessions.
	 * @return	Returns the sum of the weights of the items the robot is carrying.
	 * 			|let
	 * 			|	weight = 0
	 * 			|	for(Item item : getItems())
	 *			|		weight += item.getWeight()
	 *			|in
	 *			|	result == weight 
	 */
	@Raw
	public int getWeightOfItems(){
		int weight = 0;
		for(Item item : getItems())
			weight += item.getWeight();
		return weight;
	}
	
	/**
	 * A method that returns the (index+1)'th heaviest item.
	 * @param 	index
	 * 			Argument specifying the (index+1) item in the list.
	 * @return 	Returns 0 if the given index is invalid.
	 * 			|if(index >= getItems().size() || index < 0) then result == 0;
	 * @return	Returns the weight of the (index+1)'th heaviest item the robot is carrying when the given index is valid.
	 * 			|if(index < getItems().size() && index >= 0) then result == getItems().get(index).getWeight();
	 */
	@Raw
	public int getWeightOfItemIndex(int index){
		if(index >= getItems().size() || index < 0) return 0;
		return getItems().get(index).getWeight();
	}
	
	/**
	 * A method that returns a set of Battery objects that belong to the robot
	 * @return 	The batteries this robot possesses.
	 *			|let
	 *			|	Set<Battery> batteries = new HashSet<Battery>()
	 *			|	for (Item item : getItems())
	 *			|		if( item instanceof Battery ) 
	 *			|			batteries.add((Battery)item);
	 *			|in
	 *			|	result == batteries
	 */
	@Raw
	public Set<Battery> getBatteries(){
		Set<Battery> batteries = new HashSet<Battery>();
		for (Item item : getItems()) {
			if( item instanceof Battery ) 
				batteries.add((Battery)item);
		}
		return batteries;
	}
	/**
	 * A method that returns a set of RepairKit objects that belong to the robot
	 * @return 	The repairkits this robot possesses.
	 *			|let
	 *			|	Set<RepairKit> repairkits = new HashSet<RepairKit>()
	 *			|	for (Item item : getItems())
	 *			|		if( item instanceof RepairKit ) 
	 *			|			repairkits.add((RepairKit)item);
	 *			|in
	 *			|	result == repairkits
	 */
	@Raw
	public Set<RepairKit> getRepairKits(){
		Set<RepairKit> repairkits = new HashSet<RepairKit>();
		for (Item item : getItems()) {
			if (item instanceof RepairKit)
				repairkits.add((RepairKit) item);
		}
		return repairkits;
	}
	/**
	 * A method that returns a set of SurpriseBox objects that belong to the robot
	 * @return 	The surpriseboxes this robot possesses.
	 *			|let
	 *			|	Set<RepairKit> surpriseboxes = new HashSet<SurpriseBox>()
	 *			|	for (Item item : getItems())
	 *			|		if( item instanceof SurpriseBox ) 
	 *			|			surpriseboxes.add((SurpriseBox)item);
	 *			|in
	 *			|	result == surpriseboxes
	 */
	@Raw
	public Set<SurpriseBox> getSurpriseBoxes(){
		Set<SurpriseBox> surpriseboxes = new HashSet<SurpriseBox>();
		for (Item item : getItems()) {
			if(item instanceof SurpriseBox)
				surpriseboxes.add((SurpriseBox) item);
		}
		return surpriseboxes;
	}
	/**
	 * A method that lets this robot pick up the given item if they are placed on the same field.
	 * @param 	item
	 *        	The item which needs to be picked up
	 * @post 	If the item and the robot are on the same board and on the same field, then the item will be a possession of the robot.
	 *        	| if(this.isPlacedOnBoard() && item.isPlacedOnBoard() && item.getField().equals(this.getField())) 
	 *			|	new.this.hasItem(item) == true
	 * @post	If the item and the robot are on the same board and on the same field, then the item will be removed from that field.
	 * 			| if(this.isPlacedOnBoard() && item.isPlacedOnBoard() && item.getField().equals(this.getField()))			
	 * 			| 	new.this.getField().getBatteries().contains(item) == false
	 * @result	Returns true if the item was picked up, false if not.
	 * 			|	result == this.isPlacedOnBoard() && item.isPlacedOnBoard() && item.getField().equals(this.getField())
	 */
	@Raw
	public boolean pickUpItem(Item item)
	{
		if( this.isPlacedOnBoard() && item.isPlacedOnBoard() && item.getField().equals(this.getField()) ){
			this.getField().removeElement(item); //this makes sure that the bidirectional association between the field and the item is ended.
			this.addItem(item);
			return true;
		}
		return false;
	}
	
	/**
	 * Use the item given as parameter.
	 * @param item
	 * 			The item to use
	 * @effect	if the given item is a battery, use the battery
	 * 			|if(item instanceof Battery) then this.useBattery((Battery)item)
	 * @effect	if the give item is a repairkit, use the repairkit
	 * 			|if(item instanceof RepairKit) then this.useRepairKit((RepairKit)item)
	 * @effect	if the given item is a surprisekit, use the surprisekit
	 * 			|if(item instanceof SurpriseBox) then this.useSurpriseBox((SurpriseBox)item)
	 */
	public boolean useItem(Item item){
		if(item instanceof Battery) return this.useBattery((Battery)item);
		else if(item instanceof RepairKit) return this.useRepairKit((RepairKit)item);
		else if(item instanceof SurpriseBox) return this.useSurpriseBox((SurpriseBox)item);
		return false;
	}
	
	/**
	 * A method for a Robot to use a battery. If the battery is not terminated, the complete energy content of the battery is transferred to the Robot, 
	 * or part of it in case the energy content of the battery exceeds the capacity of the Robot. If the battery is empty, it is dropped.
	 * @param 	battery
	 * 		 	The battery which needs to be used
	 * @effect 	If the battery is a possession of the robot, the battery is drained and the energy level of the robot
	 *         	is the sum of the current energy and the energy-content of the battery (in case this sum does not exceed the max energy level of this robot).
	 *         	| if (getBatteries().contains(battery) && battery.getEnergy().getAmount() != 0
	 *         	| 	&& EnergyAmount.isValidEnergy(getEnergy().add(battery.getEnergy()), getMaxEnergy()) ) then 
	 *         	|		this.recharge(battery.getEnergy())
	 *			|		battery.setEnergy(new EnergyAmount(0))
	 *			|		this.dropItem(battery)
	 * @effect 	If the battery is a possession of the robot, and the sum of the battery's energy and the robots energy level exceeds the robots maximum energy level
	 * 			the robot's energy level is recharged to the maximum, and the battery's energy level is subtracted with the used energy.
	 *         	| if (getBatteries().contains(battery) && battery.getEnergy().getAmount() != 0
	 *         	| 	&& !EnergyAmount.isValidEnergy(getEnergy().add(battery.getEnergy()), getMaxEnergy()) ) then 
	 *			|		battery.setEnergy(this.getMaxEnergy().subtract(this.getEnergy()))
	 *	 		|		this.setEnergy(this.getMaxEnergy())
	 * @effect 	If the battery is a possession of the robot, but its energy content is 0, it is discarded.
	 * 		   	|if (getBatteries().contains(battery) && battery.getEnergy().getAmount() == 0) ) then
	 * 		   	|	dropItem(battery)
	 * @return	Returns true if the battery is possessed by the robot and has an energy content != 0.
	 * 			| result == getBatteries().contains(battery) && battery.getEnergy().getAmount() != 0
	 */
	public boolean useBattery(Battery battery)
	{
		if( !getBatteries().contains(battery)) return false;
		if( battery.getEnergy().getAmount() == 0){ this.dropItem(battery); return false; }
		if( EnergyAmount.isValidEnergy(this.getEnergy().add(battery.getEnergy()), this.getMaxEnergy() )) //battery will be drained completely
		{
			this.recharge(battery.getEnergy());
			battery.setEnergy(new EnergyAmount(0));
			this.dropItem(battery); //battery is empty, drop it
		}
		else //There is more energy available in the battery than capacity left in the robot
		{
			battery.setEnergy(this.getMaxEnergy().subtract(this.getEnergy()));
			this.setEnergy(this.getMaxEnergy());
		}
		return true;
	}
	
	/**
	 * A method for a Robot to use a RepairKit. The complete energy content of the RepairKit is used to increase the maximum
	 * energylevel of the Robot, or only part of it in case the energy content of the RepairKit would otherwise increase the maximum energylevel of the Robot
	 * above EMAX_MAX. For each Ws present in the RepairKit, the maximum energy level of the robot can be increased by 0.5 Ws. If the RepairKit is empty, it is dropped.
	 * @param 	repairkit
	 * 		 	The RepairKit which needs to be used
	 * @effect 	If the RepairKit is a possession of the robot, the RepairKit is drained and the maximum energy level of the robot
	 *         	is the sum of the current maximum energy level and half of the energy-content of the RepairKit
	 *          (in case this sum does not exceed EMAX_MAX).
	 *         	| if (getRepairKits().contains(repairkit) && repairkit.getEnergy().getAmount() != 0
	 *         	| 	&& EnergyAmount.isValidEnergy(this.getMaxEnergy().add(new EnergyAmount(repairkit.getEnergy().getAmount()/2)), EMAX_MAX) ) then 
	 *         	|		this.setMaxEnergy(getMaxEnergy().add(new EnergyAmount(repairkit.getEnergy().getAmount()/2)));
	 *			|		repairkit.setEnergy(new EnergyAmount(0))
	 *			|		this.dropItem(repairkit)
	 * @effect 	If the repairkit is a possession of the robot, and the sum of maximum energy level of the robot and half of the energy content of the repairkit exceeds EMAX_MAX,
	 * 			the robot's maximum energy level will be EMAX_MAX, and the repairkit's energy level is subtracted with the used energy.
	 *         	| if (getRepairKits().contains(battery) && repairkit.getEnergy().getAmount() != 0
	 *         	| 	&& !EnergyAmount.isValidEnergy(this.getMaxEnergy().add(new EnergyAmount(repairkit.getEnergy().getAmount()/2)), EMAX_MAX) ) then 
	 *			|		EnergyAmount energyOverflow = (this.getMaxEnergy().add(new EnergyAmount(repairkit.getEnergy().getAmount()/2))).subtract(EMAX_MAX);  
	 *			|		repairkit.setEnergy(new EnergyAmount(energyOverflow.getAmount()*2));
	 *			|		this.setMaxEnergy(EMAX_MAX);
	 * @effect 	If the repairkit is a possession of the robot, but its energy content is 0, it is discarded.
	 * 		   	|if (getRepairKits().contains(repairkit) && repairkit.getEnergy().getAmount() == 0) ) then
	 * 		   	|	dropItem(repairkit)
	 * @return	Returns true if the repairkit is possessed by the robot and has an energy content != 0.
	 * 			| result == getRepairKits().contains(repairkit) && repairkit.getEnergy().getAmount() != 0
	 */
	public boolean useRepairKit(RepairKit repairkit) {
		if (!getRepairKits().contains(repairkit))
			return false; //repairkit not a possession of the robot
		if ( repairkit.getEnergy().getAmount() == 0){
			this.dropItem(repairkit); //the repairkit is empty, drop it and return false
			return false;
		}
		if (EnergyAmount.isValidEnergy(this.getMaxEnergy().add(new EnergyAmount(repairkit.getEnergy().getAmount()/2)), EMAX_MAX)){		//This means that the repairkit can be used up completely (no overflow above the maximum maxEnergy)
			this.setMaxEnergy(getMaxEnergy().add(new EnergyAmount(repairkit.getEnergy().getAmount()/2)));
			repairkit.setEnergy(new EnergyAmount(0));
			this.dropItem(repairkit); // drop the repairkit, hence it is drained
		}
		else {//This means that there is more energy available in the repairkit than the robot can use
			//the energy overflow is defined as the max energy of this robot with the added energy from the repairkit (we know this is more than EMAX_MAX because of 'else' statement) subtracted with EMAX_MAX
			EnergyAmount energyOverflow = (this.getMaxEnergy().add(new EnergyAmount(repairkit.getEnergy().getAmount()/2))).subtract(EMAX_MAX);  
			repairkit.setEnergy(new EnergyAmount(energyOverflow.getAmount()*2)); //the energy that is left in the repairkit is the amount of the overflow * 2
			this.setMaxEnergy(EMAX_MAX); //the max energy of this robot is put to EMAX_MAX
		}
		return true;
	}
	
	/**
	 * A method for a Robot to use a surprisebox it is carrying. The surprisebox can have multiple effects, of which one is randomly
	 * chosen via the useOn(Robot) method. If a surprisebox is used, it is removed from the robot's possession since it can be only
	 * used once. If the surprisebox upon which the method is called is not a possession of the Robot, the method returns false. True is
	 * returned otherwise
	 * @param surprisebox
	 * 		  The surprisebox which need to be used
	 * @effect If the surprisebox is a possession of the robot, it is first removed from its possessions and then a random effect is chosen
	 * 		   via useOn(Robot)
	 * 		   | if(getSurpriseBoxes().contains(surprisebox)) then
	 * 		   | removeItem(surprisebox)
	 * 		   | surprisebox.useOn(this)	
	 * @return Returns true if the surprisebox is possessed by the robot
	 * 		   | result == getSurpriseBoxes().contains(surprisebox)
	 */
	public boolean useSurpriseBox(SurpriseBox surprisebox) {
		if(!getSurpriseBoxes().contains(surprisebox)) return false;
		removeItem(surprisebox); //the surprisebox is removed from the robots possessions for it is about to be used and terminated.
		surprisebox.useOn(this);
		return true;
	}
	
	/**
	 * A method for dropping an item the robot is carrying. If the robot is on a Board, it is dropped on that field. Otherwise it is simply removed from the possessions of the robot.
	 * @param 	item
	 * 		  	The item which needs to be dropped
	 * @effect 	If the item is a possession of the robot, it is removed from the robot's possessions and is placed on the field where the robot is positioned if the robot is placed on the board.
	 *         	| if(this.removeItem(item) && this.isPlacedOnBoard()) then this.getField().putElement(item)
	 * @return	Returns true if the item is a possession of the robot, false if it is not.
	 * 			| result == this.removeItem(item)
	 */
	@Raw
	public boolean dropItem(Item item)
	{
		boolean removed = this.removeItem(item); 
		if(removed && this.isPlacedOnBoard())
			this.getField().putElement(item); //if the robot is placed on the board, the item is dropped on the board
		return removed;
	}
	
	/**
	 * A method that transfers all of this robot's items to the other robot if they are positioned next to each other on the same board.
	 * @param otherRobot
	 * 			The robot to which we will transfer all of this robot's items.
	 * @return	Returns false if the robots are not next to each other on the same board or if this robot has no items to transfer, else true is returned.
	 * 			|result == Robot.isNextTo(this, otherRobot) && !this.getItems().isEmpty()
	 * @post	This robot will have no items left.
	 * 			|new.getItems().isEmpty() == true
	 * @effect	If the robots are next to each other on the same board and this robot has at least one item, All of this robot's items will be removed from its possessions and then added to the possessions of the other robot.
	 * 			|if(Robot.isNextTo(this, otherRobot) && !this.getItems().isEmpty()) then
	 * 			|	for( Item item : this.getItems().toArray(new Item[0]) )
	 * 			|		this.removeItem(item);
	 * 			|		otherRobot.addItem(item);
	 */
	@Raw
	public boolean transferItemsTo(Robot otherRobot)
	{
		if(!Robot.isNextTo(this, otherRobot) || this.getItems().isEmpty()) return false; //no items can be transfered
		for( Item item : this.getItems().toArray(new Item[0]) ){
			this.removeItem(item);
			otherRobot.addItem(item);
		}
		return true;
	}
	
	//TERMINATE
	/**
	 * Terminates this robot.
	 * @post	The robot's state is set to terminated.
	 * 			|new.isTerminated() == true
	 * @effect 	If the robot is placed on a board, it is removed from this board.
	 * 			|if(isPlacedOnBoard) then getField().removeElement(this)
	 * @effect 	The possessions of the robot are terminated as well.
	 * 			|for (Item item : getItems())
	 *			|	item.terminate();
	 *			|	this.removeItem(item);
	 */
	@Override
	public void terminate(){
		//if the robot is placed on the board, remove from board (this means we remove its reference from its field
		if(isPlacedOnBoard()) getField().removeElement(this);
		//terminate all my items
		for (Item item : getItems().toArray(new Item[0])) {
			item.terminate();
			this.removeItem(item);
		}
		//now terminate this robot by setting isTerminated to true.
		super.isTerminated = true;
	}
	
	//Shooting
	/**
	 * An EnergyAmount indicating the cost necessary to shoot
	 */
	public static final EnergyAmount ECOST_SHOOT = new EnergyAmount(1000);
	
	/**
	 * A method that allows a Robot to shoot into the direction it is oriented, hereby consuming ECOST_SHOOT Ws of energy.
	 * Shooting has the effect that the first other robot, wall, or battery located in the shooting direction is destroyed.
	 * The method is effective if and only if the robot is placed on a board.
	 * @pre		The robot should have sufficient energy to shoot.
	 * 			| hasEnergyToShoot()
	 * @post  	If the robot is placed on a board its energy level will be subtracted with ECOST_SHOOT
	 * 			| if(isPlacedOnBoard()) then new.getEnergy().equals( this.getEnergy().subtract(ECOST_SHOOT) ) == true
	 * @effect 	If the robot is placed on the board and the target field has a wall on it it will be terminated. Else if it has a robot or item on it this will be terminated. 
	 * 			|let
	 * 			|	targetField = this.getField().getBoard().getFirstFieldWithElementInDirection( this.getField(), this.getOrientation() )
	 * 			|in
	 * 			|	if(isPlacedOnBoard() && targetField != null) then
	 * 			|		if(targetField.hasWall()) then targetField.getWall().hit()
	 * 			|		else if(targetField.hasRobot()) then targetField.getRobot().hit()
	 * 			|		else if(targetField.hasItem()) then targetField.getRandomItem().hit()
	 */
	public void shoot(){
		assert hasEnergyToShoot();
		if(!isPlacedOnBoard()) return;
		
		Field targetField = this.getField().getBoard().getFirstFieldWithElementInDirection(this.getField(), this.getOrientation());
		if(targetField == null) return;
		if(targetField.hasWall()) targetField.getWall().hit();
		else if(targetField.hasRobot()) targetField.getRobot().hit();
		else if(targetField.hasItem()) targetField.getRandomItem().hit();
		
		setEnergy(getEnergy().subtract(ECOST_SHOOT));
	}
	
	/**
	 * An EnergyAmount expressing the decrease in maximum energy level a robot can experience when it is hit by another robot's laser
	 */
	public static final EnergyAmount HIT_DAMAGE = new EnergyAmount(4000);
	
	/**
	 * A method that gives the effect a robot experiences when it is hit by the laser of another robot
	 * @effect If the maximum energy level of this robot is smaller than HIT_DAMAGE, it will be terminated
	 * 			|if(getMaxEnergy().compareTo(HIT_DAMAGE) <= 0) then
	 * 			| terminate()
	 * @effect If the current energylevel of the robot is more than HIT_DAMAGE less than the maximum level, only the maximum level is decreased
	 * 			|if(EnergyAmount.isValidEnergy(getEnergy().add(HIT_DAMAGE), getMaxEnergy())) then
	 * 			| setMaxEnergy(getMaxEnergy().subtract(HIT_DAMAGE))
	 * @effect If the difference between the current energylevel and the maximum energylevel is less than HIT_DAMAGE, the maximum level will be decreased
	 * 		   with HIT_DAMAGE and the energy level is set at the same amount
	 * 			|if(!EnergyAmount.isValidEnergy(getEnergy().add(HIT_DAMAGE), getMaxEnergy())) then
	 * 			|setEnergy(getMaxEnergy().subtract(HIT_DAMAGE))
	 * 			|setMaxEnergy(getMaxEnergy().subtract(HIT_DAMAGE))
	 */
	@Override
	public void hit() {
		if(getMaxEnergy().compareTo(HIT_DAMAGE) <= 0) { //if the maxEnergy of this robot is smaller or equal to the hit damage, the robot will be terminated.
			this.terminate(); return;
		}
		//Check if the current energylevel of the robot is more than 4000 Ws less than the maximumlevel
		if(EnergyAmount.isValidEnergy(getEnergy().add(HIT_DAMAGE), getMaxEnergy())){
			this.setMaxEnergy(getMaxEnergy().subtract(HIT_DAMAGE)); //if so, we can simply subtract the hit_damage from the robots current maxEnergy
		}
		//The current energylevel of the robot would not be valid for the new maxEnergy
		else{
			setEnergy(getMaxEnergy().subtract(HIT_DAMAGE)); //we also set the energy to the new maxEnergy
			setMaxEnergy(getMaxEnergy().subtract(HIT_DAMAGE));
		}
	}
	
	//---------------------------------------------------------------------------------------------------------------------------------
	
	
	//****************************** related to orientation ***************************************************************************
	
	/**
	 * @return 	Returns the orientation of the robot as an instance of the Enum Orientation.
	 * 			|result == this.orientation
	 */
	@Basic @Raw
	public Orientation getOrientation(){ return this.orientation; }
	
	/**
	 * @param	orientation
	 * 			An instance of the Enum Orientation
	 * @post	The orientation of the robot will be set to the given orientation in case it is a valid one.
	 * 			| if(isValidOrientation(orientation)) then (this.orientation = orientation)
	 * @note 	implemented in a total way
	 */
	@Basic
	public void setOrientation(Orientation orientation)
	{	
		if(Orientation.isValidOrientation(orientation)) this.orientation = orientation;
		//if the given orientation is not valid, keep the current orientation of the robot (do nothing).
	}

	/**
	 *  Orientation instance representing the robot's orientation, referring to a UP,RIGHT,DOWN or LEFT Orientation enum instance
	 */
	private Orientation orientation;
	
	//---------------------------------------------------------------------------------------------------------------------------------
	
	//****************************** related to energy ********************************************************************************
	/**
	 * @return 	The energy-level of this robot.
	 * 			|result == this.energy
	 */
	@Basic @Raw
	public EnergyAmount getEnergy(){return this.energy;}
	
	/**
	 * @return 	The maximum energy-level of this robot.
	 * 			|result == this.maxEnergy
	 */
	@Basic @Raw
	public EnergyAmount getMaxEnergy(){return this.maxEnergy;}
	
	/**
	 * Returns a double between 0 and 1, representing the fraction of its energy with its maximum energy.
	 * @return 	Returns the ratio of the energy-level of the robot with its maximum energy-level. (as a double)
	 * 			|result == this.getEnergy().getFraction(this.getMaxEnergy())
	 */
	public double getEnergyFraction(){
		return this.getEnergy().getFraction(this.getMaxEnergy());
		}
	
	/**
	 * Calculates and returns the energy required to move for this robot.
	 * @return 	The energy required to move this robot.
	 * 			|let
	 * 			|	EnergyAmount loadCost = new EnergyAmount((this.getWeightOfItems()/1000) * ECOST_WEIGHT.getAmount())
	 * 			|in
	 * 			|	result == ECOST_MOVE.add(loadCost)
	 */
	@Raw
	public EnergyAmount getEnergyToMove(){
		EnergyAmount loadCost = new EnergyAmount((this.getWeightOfItems()/1000) * ECOST_WEIGHT.getAmount());
		return ECOST_MOVE.add(loadCost);
	}
	
	/**
	 * @return Returns true if this robot has sufficient energy to move. False if not.
	 */
	public boolean hasEnergyToMove(){
		return EnergyAmount.isValidEnergy(this.getEnergy().subtract(this.getEnergyToMove()), this.getMaxEnergy());
	}
	/**
	 * @return Returns true if this robot has sufficient energy to turn. False if not.
	 */
	public boolean hasEnergyToTurn(){
		return EnergyAmount.isValidEnergy(this.getEnergy().subtract(ECOST_TURN), this.getMaxEnergy());
	}
	/**
	 * @return Returns true if this robot has sufficient energy to shoot. False if not.
	 */
	public boolean hasEnergyToShoot(){
		return EnergyAmount.isValidEnergy(this.getEnergy().subtract(ECOST_SHOOT),this.getMaxEnergy());
	}
	
	/**
	 * @param	energy
	 * 			An energyAmount as energy level for the robot.
	 * @pre		The energy-level given as parameter should be valid.
	 * 			|EnergyAmount.isValidEnergy(energy, this.getMaxEnergy())
	 * @post	The new energy-level of the robot will be the one given as parameter.
	 * 			|new.getEnergy() == energy
	 */
	@Basic
	public void setEnergy(EnergyAmount energy){
		assert (!EnergyAmount.isValidEnergy(energy, getMaxEnergy()));
		this.energy = energy;
	}
	
	/**
	 * @param	maxEnergy
	 * 			An energyAmount as maximum energy level for the robot.
	 * @pre		The parameter maxEnergy should be a valid energy-level for the robot.
	 * 			|EnergyAmount.isValidEnergy(this.getEnergy(), maxEnergy)
	 * @post	The new maximum energy-level of the robot will be the one given as parameter.
	 * 			|new.getMaxEnergy() == maxEnergy
	 */
	@Basic
	public void setMaxEnergy(EnergyAmount maxEnergy){
		assert (!EnergyAmount.isValidEnergy(getEnergy(), maxEnergy));
		this.maxEnergy = maxEnergy;
	}
	
	/**
	 * Recharges the robot with a certain energy amount.
	 * @param 	energyAmount
	 * 			The energy amount the robot has to be recharged with.
	 * @pre		The sum of the given energy amount and the current energy-level of the robot should not be larger than the robot's max energy-level.
	 * 			|EnergyAmount.isValidEnergy(this.getEnergy().add(energyAmount), this.getMaxEnergy())
	 * @effect	The new energy-level of the robot is the sum of the old one and the energy amount given as parameter.
	 * 			|setEnergy(this.getEnergy().add(energyAmount))
	 */
	public void recharge(EnergyAmount energy){
		assert !(EnergyAmount.isValidEnergy(getEnergy().add(energy),getMaxEnergy()));
		setEnergy(getEnergy().add(energy));
	}
	
	/**
	 * 	An EnergyAmount object that represents the energy-level of this robot.
	 */
	private EnergyAmount energy;	//in Ws
	/**
	 * 	An EnergyAmount object  that represents the maximum energy-level of this robot.
	 */
	private EnergyAmount maxEnergy; //in Ws
	
	/**
	 *  ECOST_MOVE is a constant class value that represents the energy that is consumed after each move()
	 */
	public static final EnergyAmount ECOST_MOVE = new EnergyAmount(500);
	/**
	 *  ECOST_TURN is a constant class value that represents the energy that is consumed after each turn()
	 */
	public static final EnergyAmount ECOST_TURN = new EnergyAmount(100);
	/**
	 *  ECOST_WEIGHT is a constant class value that represents the energy cost for moving the robot per 1000g of load.
	 */
	public static final EnergyAmount ECOST_WEIGHT = new EnergyAmount(50);
	/**
	 * EMAX_MAX representing the default maxEnergy EnergyAmount for a robot.
	 */
	public static final EnergyAmount EMAX_MAX = new EnergyAmount(20000);
	

	//---------------------------------------------------------------------------------------------------------------------------------

	//****************************** Mutator methods, advanced inspector methods and help methods *************************************
		
	/**
	 * Turns the robot in clockwise or counterclockwise direction.
	 * @param 	clockwise
	 * 			A boolean indicating if the robot has to turn clockwise (true) or counterclockwise(false)
	 * @pre		When invoking this method the energy-level of the robot must be sufficient to turn. Turning uses ECOST_TURN Ws.
	 * 			|hasEnergyToTurn()
	 * @effect	The orientation of the robot is changed.
	 * 			|setOrientation(getOrientation().turn(clockwise));
	 * @post	The robot consumes ECOST_TURN Ws in energy
	 * 			|new.getEnergy().equals( this.getEnergy().subtract(ECOST_TURN) ) == true
	 */
	public void turn(boolean clockwise)
	{
		assert !EnergyAmount.isValidEnergy(getEnergy().subtract(ECOST_TURN),this.getMaxEnergy()); //everything energy-related is handled nominally
		setOrientation(getOrientation().turn(clockwise));
		setEnergy(getEnergy().subtract(ECOST_TURN));
	}
	
	/**
	 * When invoking this method on a Robot it will turn the Robot into the closest orientation which is a 
	 * desired orientation to make a move towards targetPos. (if this Robot has sufficient energy left to do so)
	 * @param 	targetPos
	 * 			The position towards which we want to turn our robot
	 * @effect 	If the robot is placed upon a board, it is turned to the closest orientation that is a desired orientation to move towards
	 * 			targetPos. At least if it has sufficient energy to do this.
	 * 			|if(isPlacedOnBoard())
	 * 			| double angleDiff = getField().getPosition().getDifferenceVector(targetPos).getAngleWithXAxis() - getOrientation().getAngle()
	 * 			| if(Math.floor(angleDiff) > 180.0) then angleDiff -= 360.0
	 * 			| else if( Math.floor(angleDiff) < -180.0 ) then angleDiff += 360.0
	 * 			| while( !(Math.abs(angleDiff) < 90.0) && hasEnergyToTurn() )
	 * 			|	angleDiff = this.turnByAngle(angleDiff)
	 */
	public void turnIntoDirection(Position targetPos)
	{
		if(!isPlacedOnBoard()) return;
		Position directionVector = getField().getPosition().getDifferenceVector(targetPos); 
		double angle =  directionVector.getAngleWithXAxis();
		double angleDiff = angle - getOrientation().getAngle();
		if( Math.floor(angleDiff) > 180.0) angleDiff -= 360.0;
		else if( Math.floor(angleDiff) < -180.0 ) angleDiff += 360.0;
	
		while( !(Math.abs(angleDiff) < 90.0) 
				&& hasEnergyToTurn() ){ //we assure that the precondition for turning is true
			angleDiff = this.turnByAngle(angleDiff);
		}
	}
	
	/**
	 * A method that given an 'angle' as a parameter, turns the robot clockwise if the given 'angle' is larger than 90.0
	 * and returns 'angle - 90.0'. It turns the robot counterclockwise if the 'angle' is less than -90.0 and returns 'angle + 90.0'.
	 * It returns the original angle when it is situated between -90.0 and + 90.0.
	 * @param 	angle
	 * @pre		The robot should have sufficient energy to turn.
	 * 			|this.hasEnergyToTurn()
	 * @return 	When the angle that is given as a parameter is less then 90.0 degrees in absolute value, the angle itself returned
	 * 			|if(Math.abs(angle) < 90) then result == angle
	 *			When the given angle is larger than or equal to + 90.0 degrees, the original 'angle - 90.0' is returned
	 * 			|if(angle >= 90) then result == angle - 90.0
	 * 			When the given angle is smaller than or equal to - 90.0 degrees, the original 'angle + 90.0' is returned
	 * 			|if(angle <= 90) then result == angle + 90.0
	 * @effect 	When the given angle is larger than or equal to + 90.0 degrees, the robot is turned clockwise
	 * 			|if(angle >= 90) then turn(Orientation.clockwise)
	 * @effect	When the given angle is smaller than or equal to - 90.0 degrees, the robot is turned counterclockwise
	 * 			|if(angle <= 90) then turn(Orientation.counterclockwise)
	 */
	public double turnByAngle(double angle){
		if(Math.abs(angle) < 90) return angle;
		if(angle > 0){
			turn(Orientation.clockwise);
			return angle - 90.0;
		}
		this.turn(Orientation.counterclockwise);
		return angle + 90.0;
	}
	
	/**
	 * A method which moves a robot one field in the direction it is oriented, if it has enough energy to do so. 
	 * @pre		When invoking this method the energy-level of the robot must be at least as high as the cost to move.
	 * 			|this.hasEnergyToMove()
	 * @effect	If the robot is placed on a board, an attempt is made to move the robot one field in the direction it is oriented to. If this fails, the exception
	 * 			is caught and the robot stays at its position.
	 * 			|if(isPlacedOnBoard)
	 * 			|	Field oldField = getField()
	 *			|	Board board = oldField.getBoard()
	 *			| 	Position newPosition = new Position(oldField.getPosition().getX() + this.orientation.getDx(), oldField.getPosition().getY() + this.orientation.getDy())
	 *			|	boolean isMoved = false
	 *			|	try
	 *			|		oldField.removeElement(this)
	 *			|		board.putElement(newPosition, this)
	 *			|		isMoved = true
	 *			|	catch (IllegalArgumentException argExc)
	 *			|		oldField.putElement(this)
	 *			|	catch (IllegalStateException stateExc)
	 *			|		oldField.putElement(this)
	 * @effect	The robot consumes getEnergyToMove() Ws in energy if the attempt to move it was successful
	 * 			|if(isMoved) then setEnergy(this.getEnergy().subtract(getEnergyToMove()))
	 */
	public void move()
	{
		assert this.hasEnergyToMove();
		if(!isPlacedOnBoard()) return;
		Field oldField = getField();
		Board board = oldField.getBoard();
		long newX = oldField.getPosition().getX() + this.orientation.getDx();
		long newY = oldField.getPosition().getY() + this.orientation.getDy();
		Position newPosition = new Position(newX,newY);
		
		boolean isMoved = false;
		try{
			oldField.removeElement(this);//Remove robot from its old field
			board.putElement(newPosition, this); //put the robot on its new field
			isMoved = true;
		}//place the robot back if moving to the new position resulted in an IllegalArgumentException or IllegalStateException being thrown
		catch (IllegalArgumentException argExc){
			System.err.print(argExc.getMessage());
			oldField.putElement(this); 
		}
		catch (IllegalStateException stateExc){
			System.err.print(stateExc.getMessage());
			oldField.putElement(this);
		}
		//if the moving was successful, use the energy that was needed
		if(isMoved) setEnergy(this.getEnergy().subtract(getEnergyToMove()));
	}

	/**
	 * Method that calculates the minimal energy required for this robot to move to a certain position given as parameter.
	 * @param  	position
	 * 			The position for which the energy cost of reaching it, needs to be determined
	 * @pre		There are no other elements encountered by the robot while moving towards the target position
	 * 			|let
	 * 			|	Iterator<Field> iter = this.getField().getBoard().getFieldsInUseIterator();
	 * 			|	while(iter.hasNext())
	 * 			|		Field iterField = iter.next()
	 * 			|in
	 * 			|		if(iterField != this.getField() && iterField != position.getField() 
	 * 			|			&& iterField.getField().getPosition().withinRectangleDefinedBy(this.getField().getPosition(), position)
	 * 			|				then iterField.hasElement() == false
	 * @return	Returns the minimum amount of energy required to reach a certain position. 
	 * 			This equals the consumed energy of a dummyRobot, which is a copy of the original robot, that moved along the most efficient path to this position,
	 * 			on a board which has the same size as the original board.
	 * 			|let
	 * 			|	Robot dummyRobot = new Robot(this.getOrientation(), Robot.EMAX_MAX, Robot.EMAX_MAX)
	 *			|	Board dummyBoard = new Board(getField().getBoard().getWidth(), getField().getBoard().getHeight())
	 *			|	dummyBoard.putElement(getField().getPosition(), dummyRobot)
	 *			|	EnergyAmount energyConsumed = new EnergyAmount(0)
	 *			|	while( !(dummyRobot.getField().getPosition().equals(position)) )
	 *			|		dummyRobot.moveOneFieldCloserTo(position)
	 *			|		energyConsumed = energyConsumed.add( dummyRobot.getMaxEnergy().subtract(dummyRobot.getEnergy()) )
	 *			|		dummyRobot.setEnergy(dummyRobot.getMaxEnergy())
	 *			|in
	 *			|	result == energyConsumed	
	 * @throws 	IllegalArgumentException
	 * 			An IllegalArgumentException is thrown if the given position is not a valid position on the associated board.
	 *			|!getField().getBoard().isValidPosition(position)
	 * @throws 	IllegalStateException
	 * 			If the robot is not placed on a board an IllegalStateException is thrown.
	 * 			|!isPlacedOnBoard()
	 */
	public EnergyAmount getEnergyRequiredToReach(Position position) throws IllegalArgumentException, IllegalStateException
	{
		if(!isPlacedOnBoard()) throw new IllegalStateException("The robot is not placed on a board, impossible to calculate energy required to reach "+position.toString()+".");
		if(!getField().getBoard().isValidPosition(position)) throw new IllegalArgumentException("Position is out of bounds of the board.");
		//We don't actually want to move our robot, we just want to calculate how much energy the robot would consume trying to reach that position.
		//So we make a dummyRobot as a copy of this robot, let him move to that position over the most optimal path, and return the consumed energy by that dummyRobot. 
		Robot dummyRobot = new Robot(this.getOrientation(), Robot.EMAX_MAX, Robot.EMAX_MAX);
		Board dummyBoard = new Board(getField().getBoard().getWidth(), getField().getBoard().getHeight()); //make a dummy board for the dummy robot to move on
		dummyBoard.putElement(getField().getPosition(), dummyRobot);
		
		EnergyAmount energyConsumed = new EnergyAmount(0);
		while( !(dummyRobot.getField().getPosition().equals(position)) ) //while the robot has not arrived on the destination
		{
			dummyRobot.moveOneFieldCloserTo(position);
			energyConsumed = energyConsumed.add( dummyRobot.getMaxEnergy().subtract(dummyRobot.getEnergy()) );
			dummyRobot.setEnergy(dummyRobot.getMaxEnergy());
		}
		//the dummyRobot has moved over the most efficient path with no inefficient turns and has arrived on the destination
		return energyConsumed;
	}
	
	/**
	 * A static method that, given two robots, moves these two robots as closely as possible given their energy-levels. When their energy-levels are sufficient they end up next to each other, 
	 * if not they end up as close as possible up to where their energy-level allows. It is assumed that there are no obstacles between the two robots that would block the most efficient path.
	 * @param 	robot1
	 * 		  	the first robot
	 * @param 	robot2
	 * 		  	the second robot
	 * @pre		There are no other elements encountered by the robots while moving along the calculated path.
	 * 			|let
	 * 			|	Iterator<Field> iter = otherBoard.getFieldsInUseIterator();
	 * 			|	while(iter.hasNext())
	 * 			|		Field iterField = iter.next()
	 * 			|in
	 * 			|		if(iterField != robot1.getField() && iterField != robot2.getField() 
	 * 			|			&& iterField.getField().getPosition().withinRectangleDefinedBy(robot1.getField().getPosition(), robot2.getField().getPosition())
	 * 			|				then iterField.hasElement() == false
	 * @effect	As long as the robots are not next to each other and at least one of the robots has sufficient energy to move, we move them one field closer to each other.
	 * 			|while( !Robot.isNextTo(robotFirst,robotLast) && (robotFirst.hasEnergyToMove() || robotLast.hasEnergyToMove()) )
	 * 			|	robotFirst.moveOneFieldCloserTo(robotLast.getField().getPosition())
	 *			|	if(!Robot.isNextTo(robotFirst,robotLast)) then 
	 *			|		robotLast.moveOneFieldCloserTo(robotFirst.getField().getPosition())
	 */
	public static void moveNextTo(Robot robot1, Robot robot2)
	{
		//We let the robot with the most energy move first
		Robot robotFirst = robot1;
		Robot robotLast = robot2;
		if( robot1.getEnergy().compareTo(robot2.getEnergy()) < 0 ){
			robotFirst = robot2;
			robotLast = robot1;
		}
		
		//while the robots are not next to each other and at least one of the robots has sufficient energy to move
		while( !Robot.isNextTo(robotFirst,robotLast) && (robotFirst.hasEnergyToMove() || robotLast.hasEnergyToMove()) )
		{	
			robotFirst.moveOneFieldCloserTo(robotLast.getField().getPosition());
			if(!Robot.isNextTo(robotFirst,robotLast)) //if they are not already next to each other after moving the first robot, we also move the last robot a field closer to the other one. 
				robotLast.moveOneFieldCloserTo(robotFirst.getField().getPosition());
		}
	}
	
	/**
	 * Checks if two robots are next to each other.
	 * @param 	robot1
	 * 		  	the first robot
	 * @param 	robot2
	 * 		  	the second robot
	 * @return 	returns true if the Manhattan-distance between the robots is exactly one in x or y direction 
	 * 			|result == (|dx| == 1 && |dy| == 0) || (|dx| == 0 && |dy| == 1);
	 */
	public static boolean isNextTo(Robot robot1, Robot robot2)
	{
		if(!robot1.getField().getBoard().equals(robot2.getField().getBoard())) return false; //if the robots are not located on the same board, return false
		long dx = Math.abs(robot1.getField().getPosition().getX() - robot2.getField().getPosition().getX());
		long dy = Math.abs(robot1.getField().getPosition().getY() - robot2.getField().getPosition().getY());
		return (dx == 1 && dy == 0) || (dx == 0 && dy == 1);
	}
	

	/**
	 * A method that turns its prime object into a desired orientation if needed (to move towards the target position) 
	 * and then moves the robot one field closer towards the position if it has sufficient energy to do so.
	 * @param 	position
	 * 			The position towards which we want this robot to move one field closer to.
	 * @throws	IllegalArgumentException
	 * 			An IllegalArgumentException is thrown when the position given in the parameters is invalid.
	 * 			|!getField().getBoard().isValidPosition(position)
	 * @effect	The robot is turned into a desired direction towards the given position (if the given position is not the same as the robots position)
	 * 			| if( !position.equals(this.getField().getPosition() ) then turnIntoDirection(position)
	 * @effect	If the robot has sufficient energy to move, it is moved one field in its orientation.
	 * 			| if(!position.equals(this.getField().getPosition() && hasEnergyToMove() ) then this.move() 
	 */
	public void moveOneFieldCloserTo(Position position) throws IllegalArgumentException
	{ 
		if(!getField().getBoard().isValidPosition(position)) throw new IllegalArgumentException("Position is out of bounds of the board."); //position is handled defensively
		if(position.equals(this.getField().getPosition())) return;
		this.turnIntoDirection(position);
		//we check if the robot has enough energy to move, in case not we cannot help the robot get any further towards its destination. return.
		if(!hasEnergyToMove()) return; //energy is handled nominally, we assure that the precondition is satisfied.
		this.move();
	}
	
	/**
	 * Returns a boolean indicating whether or not this robot can be placed on the same field as the given element.
	 * @return 	|if(otherElement == this) then result == true
	 * 			|else if( otherElement instanceof Robot ) then result == false
	 * 			|else then result == otherElement.canHaveSameFieldAs(this) 
	 */
	@Override
	public boolean canHaveSameFieldAs(Element otherElement) {
		if(otherElement == this) return true;
		if(otherElement instanceof Robot) return false;
		return otherElement.canHaveSameFieldAs(this);
	}
	
	/**
	 * @return	A string representing this robot with all its components. 
	 * @note This is shown when hovering over the robot in RoboRally main.
	 */
	@Override
	public String toString(){
		String sfield;
		if(isPlacedOnBoard()) sfield = getField().toString();
		else sfield = "not on board";
		String s = "energy: " + getEnergy().getAmount()+"/(max)"+getMaxEnergy().getAmount() + "| field: " + sfield+ "| terminated:" + isTerminated()+"|";
		int i = 0;
		for (Item item : getItems())
			s += ", item_"+i+" "+item.toString();
		return s;
	}
	//------------------------------------------------------------------------------------------------------------------------------------------
	
	//****************************** Program related *************************************
	/**
	 * The associated program the robot can execute.
	 * @note A robot is never initialized with a program. If you want to assign a program to a robot you must call loadProgram(String filePath) first.
	 */
	private Program myProgram;

	/**
	 * 
	 * @return The Program which is linked to this robot
	 * 			|result == this.myProgram
	 */
	@Basic
	public Program getProgram() { return myProgram; }
	
	/**
	 * 
	 * @param myProgram
	 * 		  The program given as a parameter which needs to be set for this robot
	 * @effect The program linked to this robot equals myProgram
	 * 			|this.getProgram() == myProgram
	 */
	@Basic
	public void setProgram(Program myProgram) { this.myProgram = myProgram; }
	/**
	 * Loads a program for this robot.
	 * @param 	filePath
	 * 			The path to the source file (.prog)
	 * @effect	The new program constructed from the filePath is associated with this robot.
	 * 			|setProgram(new Program(this, filePath))
	 */
	public void loadProgram(String filePath) throws IOException,IllegalArgumentException{
		this.setProgram(new Program(this, filePath));
	}
	
	//------------------------------------------------------------------------------------

	
}
